package log.aop;


import com.alibaba.fastjson.JSONObject;
import com.common.enums.LoginTypeEnum;
import com.common.exception.MyException;
import com.common.result.Result;
import com.common.result.ResultCode;
import log.annotation.OperationLog;
import log.constant.LogConstants;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author
 * @Desc
 * @date 2021/6/30 9:27
 */
@Slf4j
@Aspect
@Order(1)
@Component
// todo 待优化
public class DatabaseOperateAspect extends BaseAspect {

    @Value("${run.type:remote}")
    private String runType;
//    @Resource
//    private LogApi logApi;

    /***/
    @Pointcut("@annotation(log.annotation.OperationLog)")
    public void pointCut() {
    }

    /***/
    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        String param = super.getRequestParams(point);
        Result result = (Result) point.proceed();
        int code = 0;
        if (null != result) {
            code = ResultCode.SUCCESS.getCode().equals(result.getCode()) ? LogConstants.SUCCES : LogConstants.FAIL;
        }
        if (!LoginTypeEnum.LOCAL.getValue().equals(runType)) {
            saveLog(param, point, code, null);
        }
        return result;
    }

    /**
     * 异常-日志记录
     *
     * @param exception
     */
    @AfterThrowing(value = "pointCut()", throwing = "exception")
    public void doAfterThrowingAdvice(JoinPoint point, Throwable exception) {
        String param = super.getRequestParams(point);
        int responseCode = LogConstants.EXCEPTION;
        String mgs = MyException.printToStr(exception);
        if (exception instanceof MyException) {
            MyException e = (MyException) exception;
            if (e.getResultCode() == null) {
                responseCode = LogConstants.FAIL;
                mgs = exception.getMessage();
            } else if (!e.getResultCode().getCode().equals(ResultCode.SYSTEM_ERROR.getCode())) {
                responseCode = LogConstants.FAIL;
                mgs = exception.getMessage();
            }
        } else if (exception instanceof IllegalArgumentException) {
            responseCode = LogConstants.FAIL;
            mgs = exception.getMessage();
        }
        if (!LoginTypeEnum.LOCAL.getValue().equals(runType)) {
            saveLog(param, point, responseCode, mgs);
        }
    }

    private void saveLog(String param, JoinPoint point, int code, String exMsg) {
        // 获取方法上的注解,判断是否需要写入日志
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        StringBuffer requestUrl = new StringBuffer();
        requestUrl.append(request.getScheme());
        requestUrl.append("://");
        requestUrl.append(request.getServerName());
        requestUrl.append(":");
        requestUrl.append(request.getServerPort());
        requestUrl.append(request.getRequestURI());

//        SysLogDTO sysLog = new SysLogDTO();
//        sysLog.setRequestIp(IpUtils.getClientIpAddr(request));
//        sysLog.setRequestUrl(request.getRequestURI());
//        sysLog.setLogSystem(request.getHeader("serverName"));
//        OperationLog operationLog = method.getAnnotation(OperationLog.class);
//        // 只记录异常或者 日志注解的日志
//        if (null == operationLog) {
//            if (!(code == LogConstants.EXCEPTION || code == LogConstants.FAIL)) {
//                return;
//            }
//        }
//        if (null != operationLog) {
//            sysLog.setRequestDesc(StringUtils.hasText(operationLog.value()) ? operationLog.value() : "");
//        }
//        param = subParam(param, point, code);
//        if (param != null && param.length() > LogConstants.OUTSIZE) {
//            param = param.substring(0, LogConstants.OUTSIZE) + "...";
//        }
//        sysLog.setRequestParams(param);
//        sysLog.setResponseCode(code);
//        sysLog.setExceptionMsg(exMsg != null && exMsg.length() > 5000 ? exMsg.substring(0, 5000) : exMsg);
//        sysLog.setCreateTime(new Date());
//
//        String userId = request.getHeader("userInfo");
//        if (userId != null) {
//            try {
//                userId = URLDecoder.decode(userId, StandardCharsets.UTF_8.toString());
//            } catch (UnsupportedEncodingException e) {
//                throw new RuntimeException(e.getMessage(), e);
//            }
//            JSONObject jsonObject = JSONObject.parseObject(userId);
//            sysLog.setUserId(jsonObject.getLong("id"));
//        }
//        if (request.getRequestURI().contains(LogConstants.API)) {
//            SysApiLogDTO sysApiLog = createSysApiLog(sysLog);
//            logApi.addSysApiLog(sysApiLog);
//        } else {
//            logApi.add(sysLog);
//        }
    }

    /**
     * 获取指定参数
     *
     * @param param
     * @param point
     * @param code
     * @return
     */
    private String subParam(String param, JoinPoint point, int code) {
        // 获取方法上的注解,判断是否需要写入日志
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        // 只记录异常或者 日志注解的日志
        if (null == operationLog) {
            if (!(code == LogConstants.EXCEPTION || code == LogConstants.FAIL)) {
                return null;
            }
        }
        JSONObject newParam = new JSONObject();
        if (null != operationLog) {
            String paramStr = operationLog.param();
            if (null == paramStr || "".equals(paramStr)) {
                return param;
            } else {
                String[] paramName = operationLog.param().split(",");
                JSONObject jsonObject = JSONObject.parseObject(param);
                for (String item : paramName) {
                    newParam.put(item, jsonObject.get(item));
                }
            }
        }
        return newParam.toJSONString();
    }

//    private SysApiLogDTO createSysApiLog(SysLogDTO sysLog) {
//        SysApiLogDTO sysApiLog = new SysApiLogDTO();
//        BeanUtils.copyProperties(sysLog, sysApiLog);
//        return sysApiLog;
//    }
}
